#include "Task.hpp"

const int processnum = 5;

std::vector<task_t> tasks;

class channel
{
public:
    channel(int cmdfd, pid_t slaverid, std::string processname)
	:_cmdfd(cmdfd), _slaverid(slaverid), _processname(processname)
	{}
	
    int _cmdfd;
    pid_t _slaverid;
    std::string _processname;
};

//debug
void debug(const std::vector<channel>& channels)
{
    for(auto& a : channels)
    {
	std::cout << " pipefd: " << a._cmdfd << " child pid: " << a._slaverid << " name: " << a._processname << std::endl;
    }
}

void slaver()
{
    while(true)
    {
 	   int cmdcode = 0;

 	   //向管道中读取4个字节的数据，任务码
 	   ssize_t n = read(0, &cmdcode, sizeof(cmdcode));

 	   if(n == sizeof(cmdcode))
 	   {
 	       std::cout << " get a command: " << getpid() << " cmdcode " << cmdcode << " " << std::endl;
 	       //开始执行任务
 	       if(cmdcode >= 0 && cmdcode < tasks.size()) tasks[cmdcode](); 
 	   }
 	   
 		if(n == 0) return;
		sleep(1);
    }

}

void menu()
{
    std::cout << "**************************" << std::endl;
    std::cout << "1.等级提升      2.友方阵亡" << std::endl;
    std::cout << "3.敌方阵亡                " << std::endl;
    std::cout << "4.史诗级野怪刷新          " << std::endl;
    std::cout << "**************************" << std::endl;
}

//格式规范
//输入型参数: const &
//输出: *
//输入输出: &
void InitProcessPool(std::vector<channel>* channels)
{
	//version 2:创建一个数组来保存子进程继承父进程多余的写端，然后遍历关掉他
	//注意不能关闭父端的写端，因为他是在使用的管道文件的写端
	std::vector<int> older;
	for(int i = 0; i < processnum; i++)
	{
	    //创建匿名管道
	    int pipefd[N];
	    int n = pipe(pipefd);
	    assert(!n);
	    (void)n;

	    pid_t id = fork();
	    //child read 
	    if(id == 0)
	    {
			std::cout << "fd: ";
			//在子进程中关闭继承父进程多余的写端
			for(const auto& fd : older)
			{
				std::cout << fd << " ";
				close(fd);
			}
			std::cout << std::endl;

			close(pipefd[1]);
			dup2(pipefd[0], 0);
			//一次向管道传输4字节
			close(pipefd[0]);
			slaver();
			//close(pipefd[0]);
			exit(0);
	    }

	    //parent write
	    close(pipefd[0]);
	    std::string name = "process-" + std::to_string(i);
	    channels->push_back(channel(pipefd[1], id, name));

		//保存写端
		older.push_back(pipefd[1]);

	    sleep(2);
	}	
	   // debug(*channels);
}

void ctrlslaver(const std::vector<channel>& channels)
{
    while(true)
    {
        // int cmdcode = 0;
	    int select = 0;
        //菜单
        menu();
	
	    std::cin >> select;
		//数组下标从0开始
		select--;
       select %= tasks.size();
	    //随机使用进程,负载均衡，不要一直使用一个进程
	    //1.选择任务
	    //int cmdcode = rand() % tasks.size();
	    //cmdcode = select;
	    
	    //2.选择进程
	    int processpos = rand() % channels.size();
	
	    //3.发送任务
	    if(select >= 0 && select <= tasks.size())
	    write(channels[processpos]._cmdfd, &select, sizeof(select));
		sleep(1);
    }
}

void QuitProcess(std::vector<channel>* channels)
{
	//清理资源
	//1. 关闭文件描述符
	//2. 回收子进程

	//子进程继承父进程多个写端

	for(auto e : *channels)
	{
        close(e._cmdfd);
	    waitpid(e._slaverid, nullptr, 0);
	}

	// //version 1 ：从最后一个子进程往前关闭
	// int last = channels->size();
	// for(int i = last; i > 0; --i)
	// {
	// 	close((*channels)[i]._cmdfd);
	// 	waitpid((*channels)[i]._slaverid, nullptr, 0);
	// }
	
}

int main()
{
    //加载任务
    loadtask(&tasks);

    //设置一个随机数种子
    srand((unsigned)time(nullptr) ^ getpid() ^ 1024);
    
    //组织进程池
    std::vector<channel> channels;

    //1.初始化
    InitProcessPool(&channels);

    //2.控制子进程
    //ctrlslaver(channels);

    //3.清理资源
    //QuitProcess(&channels);
    

    return 0;
}



